#include "stdafx.h"
#include "Render.h"

#include "IWindow.h"
#include "Font.h"
#include "TextureManager.h"
#include "2DRender.h"


CRender::CRender()
: m_pFont(nullptr)
, m_p2DRender(nullptr)
{
	
}

CRender::~CRender()
{
	delete m_pFont;
	delete m_p2DRender;
	delete g_pTextureManager;

	delete g_pRenderAPI;
}

bool CRender::Init()
{
	g_pRenderAPI = LoadRenderAPIModule(DX9_LIB_NAME);
	if (!g_pRenderAPI)
		return false;

	//	init texture manager
	g_pTextureManager = new CTextureManager();

	//	init font manager
	m_pFont = new CFont("courier_new_bold.ttf", 11);
	if (!m_pFont->Init())
		return false;

	m_p2DRender = new C2DRender();

	return true;
}

void CRender::Update()
{

}

void CRender::PreRender()
{
	PROFILE_FUNCTION();

	ClearBuffer(eClearFlag_All, Color::Black, 1.0f);
	g_pRenderAPI->StartRendering();
}

void CRender::Render()
{
	float frame_time = gEnv->pTimer->GetFrameTime();
	float frame_time_ms = frame_time * 1000;
	float fps = gEnv->pTimer->GetFPS(eFPS_Instant);

	static float avg_fps_value = 0;
	static float avg_fps_rate = 0;
	Smooth(avg_fps_value, avg_fps_rate, fps, frame_time, 0.1f);

	string text = string_utils::format("%.1f fps (%.2f ms)", avg_fps_value, frame_time_ms);
	m_pFont->RenderText(text.c_str(), 10, 10, Color::Green);
}

void CRender::PostRender()
{
	PROFILE_FUNCTION();

	m_pFont->Flush();
	m_p2DRender->Flush();

	//	present backbuffer on screen
	g_pRenderAPI->FinishRendering();
	g_pRenderAPI->SwapBuffers();
}

void CRender::ClearBuffer(uint flags, const Color& color, float z)
{
	g_pRenderAPI->ClearBuffer(flags, color, z);
}

uint CRender::GetWidth() const
{
	return gEnv->pSystem->GetWindow()->GetClientWidth();
}

uint CRender::GetHeight() const
{
	return gEnv->pSystem->GetWindow()->GetClientHeight();
}

void CRender::SetShader(const char* name)
{
	IShader* pShader = name ? g_pRenderAPI->CreateShader(name) : nullptr;
	g_pRenderAPI->SetShader(pShader);
}

void CRender::SetTexture(TextureId texture)
{
	ITexture* pTexture = g_pTextureManager->GetTexture(texture);
	g_pRenderAPI->SetTexture(pTexture);
}

void CRender::DrawPrimitives(EPrimitiveType ptype, const S2DVertex* vertices, uint16 vertex_count, const uint16* indices, uint16 index_count)
{
	assert(vertices);
	assert(indices);
	assert(vertex_count > 2);

	//	vertex buffer
	uint vbuffer_size = vertex_count * sizeof(S2DVertex);

	IVertexBuffer* vb = g_pRenderAPI->CreateVertexBuffer(vbuffer_size, false);
	void* pBuffer = vb->Lock(0, vbuffer_size, eVBLock_Discard);
	memcpy(pBuffer, vertices, vbuffer_size);
	vb->Unlock();

	//	index buffer
	uint ibuffer_size = index_count * sizeof(uint16);

	IIndexBuffer* ib = g_pRenderAPI->CreateIndexBuffer(ibuffer_size, false);
	pBuffer = ib->Lock(0, ibuffer_size, eIBLock_Discard);
	memcpy(pBuffer, indices, ibuffer_size);
	ib->Unlock();

	//	render
	DrawPrimitives(ptype, vb, vertex_count, ib, index_count);

	delete vb;
	delete ib;
}

void CRender::DrawPrimitives(EPrimitiveType ptype, const IVertexBuffer* vertices, uint16 vertex_count, const IIndexBuffer* indices, uint16 index_count)
{
	PROFILE_FUNCTION();
	g_pRenderAPI->DrawPrimitives(ptype, vertices, vertex_count, indices, index_count);
}

IFont* CRender::GetFont()
{
	return m_pFont;
}

I2DRender* CRender::Get2DRender()
{
	return m_p2DRender;
}